#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/unistd.h>
#include <linux/time.h>
#include <asm/uaccess.h>
#include <linux/sched.h>
#include <uapi/asm/processor-flags.h> //X86_CR0_WP
#include <asm/special_insns.h> //read_cr0(),write_cr0()

#define SYS_SLAM 314
#define SYS_CALL_TABLE_ADDR 0xffffffff818013c0

/*Write Protect (bit 16 of CR0) 
* When set, inhibits supervisor-level procedures from writing into read-only pages; 
* when clear, allows supervisor-level procedures to write into read-only pages.
*/
//reference:arch/x86/include/uapi/asm/processor-flags.h
//X86_CR0_WP

unsigned long * sys_call_table = 0;
static long (*orig_saved)(void);

MODULE_AUTHOR("X-SLAM");
MODULE_LICENSE("GPL");

asmlinkage long sys_new_slam(void)
{
	printk("I'm new_slam.current->comm=%s\n", current->comm);
	return current->pid;
}

static __init int syscall_module_init(void)
{
	unsigned long cr0;
	cr0 = read_cr0();
	write_cr0(cr0 & ~X86_CR0_WP);

	sys_call_table = (unsigned long *)SYS_CALL_TABLE_ADDR;
	orig_saved = (long(*)(void))(sys_call_table[SYS_SLAM]);
	sys_call_table[SYS_SLAM] = (unsigned long)&sys_new_slam;

	write_cr0(cr0);
	return 0;
}

static __exit void syscall_module_exit(void)
{
        unsigned long cr0;
        cr0 = read_cr0();
        write_cr0(cr0 & ~X86_CR0_WP);

	sys_call_table[SYS_SLAM] = (unsigned long)orig_saved;

	write_cr0(cr0);
}

module_init(syscall_module_init);
module_exit(syscall_module_exit);
